home *** CD-ROM | disk | FTP | other *** search
- /*
- * ANSI C code from the article
- * "Fast Embossing Effects on Raster Image Data"
- * by John Schlag, jfs@kerner.com
- * in "Graphics Gems IV", Academic Press, 1994
- *
- *
- * Emboss - shade 24-bit pixels using a single distant light source.
- * Normals are obtained by differentiating a monochrome 'bump' image.
- * The unary case ('texture' == NULL) uses the shading result as output.
- * The binary case multiples the optional 'texture' image by the shade.
- * Images are in row major order with interleaved color components (rgbrgb...).
- * E.g., component c of pixel x,y of 'dst' is dst[3*(y*xSize + x) + c].
- *
- * To compile a test program on an SGI:
- * cc -DMAIN emboss.c -lgl_s -lm -o emboss
- * The code for the Emboss routine itself is portable to most machines.
- */
-
- #include <math.h>
- #include <sys/types.h>
-
- void
- Emboss(
- double azimuth, double elevation, /* light source direction */
- u_short width45, /* filter width */
- u_char *bump, /* monochrome bump image */
- u_char *texture, u_char *dst, /* texture & output images */
- u_short xSize, u_short ySize /* image size */
- )
- {
- long Nx, Ny, Nz, Lx, Ly, Lz, Nz2, NzLz, NdotL;
- register u_char *s1, *s2, *s3, shade, background;
- register u_short x, y;
-
- #define pixelScale 255.9
-
- /*
- * compute the light vector from the input parameters.
- * normalize the length to pixelScale for fast shading calculation.
- */
- Lx = cos(azimuth) * cos(elevation) * pixelScale;
- Ly = sin(azimuth) * cos(elevation) * pixelScale;
- Lz = sin(elevation) * pixelScale;
-
- /*
- * constant z component of image surface normal - this depends on the
- * image slope we wish to associate with an angle of 45 degrees, which
- * depends on the width of the filter used to produce the source image.
- */
- Nz = (6 * 255) / width45;
- Nz2 = Nz * Nz;
- NzLz = Nz * Lz;
-
- /* optimization for vertical normals: L.[0 0 1] */
- background = Lz;
-
- /* mung pixels, avoiding edge pixels */
- dst += xSize*3;
- if (texture) texture += xSize*3;
- for (y = 1; y < ySize-1; y++, bump += xSize, dst += 3)
- {
- s1 = bump + 1;
- s2 = s1 + xSize;
- s3 = s2 + xSize;
- dst += 3;
- if (texture) texture += 3;
- for (x = 1; x < xSize-1; x++, s1++, s2++, s3++)
- {
- /*
- * compute the normal from the bump map. the type of the expression
- * before the cast is compiler dependent. in some cases the sum is
- * unsigned, in others it is signed. ergo, cast to signed.
- */
- Nx = (int)(s1[-1] + s2[-1] + s3[-1] - s1[1] - s2[1] - s3[1]);
- Ny = (int)(s3[-1] + s3[0] + s3[1] - s1[-1] - s1[0] - s1[1]);
-
- /* shade with distant light source */
- if ( Nx == 0 && Ny == 0 )
- shade = background;
- else if ( (NdotL = Nx*Lx + Ny*Ly + NzLz) < 0 )
- shade = 0;
- else
- shade = NdotL / sqrt(Nx*Nx + Ny*Ny + Nz2);
-
- /* do something with the shading result */
- if ( texture ) {
- *dst++ = (*texture++ * shade) >> 8;
- *dst++ = (*texture++ * shade) >> 8;
- *dst++ = (*texture++ * shade) >> 8;
- }
- else {
- *dst++ = shade;
- *dst++ = shade;
- *dst++ = shade;
- }
- }
- if (texture) texture += 3;
- }
- }
-
- #ifdef MAIN
-
- #define TEXTURE 1
-
- main()
- {
- #define xSize 200
- #define ySize 200
- u_char bump[ySize][xSize];
- u_char texture[ySize][xSize][3], *txt = 0;
- u_char dst[ySize][xSize][3];
- int i, j;
-
- /* make a simple input image */
- memset(bump, 0, sizeof(bump));
- for(i = xSize/4; i < 3*xSize/4; i++)
- for(j = ySize/4; j < 3*ySize/4; j++)
- bump[j][i] = 128;
-
- #if TEXTURE
- /* make a texture */
- for(i = 0; i < xSize; i++)
- for(j = 0; j < ySize; j++) {
- texture[j][i][0] = random() >> (31 - 8);
- texture[j][i][1] = random() >> (31 - 8);
- texture[j][i][2] = random() >> (31 - 8);
- }
- txt = (u_char *)texture;
- #endif
-
- /* emboss it */
- memset(dst, 0, sizeof(dst));
- #define dToR(d) ((d)*(M_PI/180))
- Emboss(dToR(30), dToR(30), 3, (u_char *)bump, txt, (u_char *)dst,
- xSize, ySize);
-
- /* display it (sgi component order is ABGR) */
- prefsize(xSize, ySize);
- winopen("emboss");
- RGBmode();
- gconfig();
- for(i = 0; i < ySize; i++) {
- u_long line[xSize];
- u_char *lp = (u_char *)line;
- for(j = 0; j < xSize; j++) {
- *lp++ = 255;
- *lp++ = dst[i][j][2];
- *lp++ = dst[i][j][1];
- *lp++ = dst[i][j][0];
- }
- lrectwrite(0, ySize-1 - i, xSize-1, ySize-1 - i, line);
- }
- sleep(30);
- }
-
- #endif
-